除了顺序结构外,所有的控制结构都要依赖布尔表达式的求值
使用 true 和 false 做布尔判断
请在布尔表达式的判断里使用 true 和 false 来代表真和假,而不要用 0 和 1 等数值。如果你的语言不直接支持这些写法,那么就用预处理宏或者全局变量来创建它们。
使用 0 和 1等数值的坏处是:降低了可读性,而且意义有时是非常含混的,有时你甚至不能确定它是否是用来做布尔判断的
隐式地比较布尔值,可以使判断语句更清晰
把表达式作为布尔表达式(而不需要“画蛇添足”地再和 true/false 直接比较一次),可以让表达式里的项数更少、可读性更高(更像英语中的对话)
画蛇添足的直接比较:
1 | if (printerError == False): |
隐式比较:
1 | if (not printerError): |
简化复杂的表达式
判断中项数很多的情况
将复杂的表达式拆分
将原来复杂的判断拆分为几个小部分,将每个小部分的判断结果赋给一些新的布尔变量,再用这些新的布尔变量组合成一个较简单的判断
衡量复杂与简单是根据布尔逻辑判断的项数
将复杂的表达式提取为布尔函数
即使这个复杂的判断只用一次,下面的做法也很有必要,因为可以改善可读性,更加集中于对主程序中整体流程的理解。具体是:将这个判断的过程提取到一个命名良好的子程序里,然后在主程序中判断这个子程序的返回值即可。这个子程序的名字也在主程序中引入了一个抽象,成为一种自说明。
toExemplify-book
涉及到多个变量的复杂判断
使用决策表来代替复杂的条件
具体参考 [[表驱动法]]
编写肯定形式的布尔表达式
否定形式的逻辑表达式可能会让人一时转不过弯,转换为肯定形式会更加清晰
在 if else 语句中
可以把判断条件从否定形式转换为肯定形式,并互换 if 和 else 子句中的代码
这条建议可能会和“在 if 子句中先处理高频的情况”(参考[[……]])冲突,可以配合下一条建议(更改名字)使用
逆转含义,更换变量的名字
如将 !statusOK
替换成 errorDetected
利用狄摩根定理
toExemplify-book
用括号使布尔表达式更清晰
使用括号降低了对代码阅读者的要求,不再要求他们对该语言的求值优先级很熟练。对于你来说,如果拿不准优先级,使用括号也是非常好的解决方法
使用如下技巧使得括号准确配对
toExemplify-book
现在一般在编辑器中都有这个功能了
把布尔表达式全部括在括号里面
这样能够改善可读性
理解布尔表达式的求值方式
不同语言下对布尔表达式的求值方式可能不同,尤其是要注意是否采用“短路(short-circuit)”求值(或者称为惰性lazy求值)
短路求值
“短路”and:从左往右继续计算,如果发现有一个操作数(operand)为假,则跳过剩余的计算
“短路”or:从左往右继续计算,如果发现有一个操作数(operand)为真,则跳过剩余的计算
用处是:利用这一性质,恰当书写求值顺序,就可以减少判断语句的书写
逻辑运算符 & 和 |
Java 中的逻辑运算符 &
和 |
会保证,所有的项都会经过完整的求值
例子
toExemplify-book
按照数轴的顺序来书写数值表达式
具体操作是:从左到右、从小到大地排列元素(常量和变量)。这样会很直观地确定变量所需要的范围
如:
1 | MIN_ELEMENTS <= i and i <= Max_ELEMENTS |
toExemplify-book-pic
与 0 比较时的指导原则
一句话,当 0 作为布尔变量时,隐式比较;其他情况,显式比较
当 0 作为字符终止符、空指针时,上面的建议虽然有违既成的 C 传统,但随之也带来了可读性的改善
toNote
布尔表达式的常见问题
在 C 家族语言中,可以使用把常量放在比较的左端这一技巧
toNote
作者偏向于数轴排序法
在 C++中,可以考虑创建预处理宏来替换 &&、||、==(不得已才这样做)
一般不这样做, 所以,toNote
在 Java 中,要理解 a==b 和 a.equals(b) 的差异
a==b
:判断的是 a 和 b 是否引用了同一个对象,即比较的是地址
a.equals(b)
:判断这两个对象是否具有相同的值
一般来说,应该使用 a.equals(b)
这样的表达式